<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>随智阔的博客
        学习 html,js,css 而建立这个静态站点
        邮箱: 442518843@qq.com</title>
    <style>
        html, body {
            overflow: hidden;
            background: black;
            padding: 0;
            margin: 0;
        }
    </style>
</head>
<body>

</body>
<script>
    "use strict";

    const {
        PI,
        cos,
        sin,
        tan,
        abs,
        sqrt,
        pow,
        min,
        max,
        ceil,
        floor,
        round,
        random,
        atan2
    } = Math;
    const HALF_PI = 0.5 * PI;
    const QUART_PI = 0.25 * PI;
    const TAU = 2 * PI;
    const TO_RAD = PI / 180;
    const G = 6.67 * pow(10, -11);
    const EPSILON = 2.220446049250313e-16;
    const rand = n => n * random();
    const randIn = (_min, _max) => rand(_max - _min) + _min;
    const randRange = n => n - rand(2 * n);
    const fadeIn = (t, m) => t / m;
    const fadeOut = (t, m) => (m - t) / m;
    const fadeInOut = (t, m) => {
        let hm = 0.5 * m;
        return abs((t + hm) % m - hm) / hm;
    };
    const dist = (x1, y1, x2, y2) => sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
    const angle = (x1, y1, x2, y2) => atan2(y2 - y1, x2 - x1);
    const lerp = (a, b, amt) => (1 - amt) * a + amt * b;
    const vh = p => p * window.innerHeight * 0.01;
    const vw = p => p * window.innerWidth * 0.01;
    const vmin = p => min(vh(p), vw(p));
    const vmax = p => max(vh(p), vw(p));
    const clamp = (n, _min, _max) => min(max(n, _min), _max);
    const norm = (n, _min, _max) => (n - _min) / (_max - _min);

    Array.prototype.lerp = function (t = [], a = 0) {
        this.forEach((n, i) => (this[i] = lerp(n, t[i], a)));
    };

    Float32Array.prototype.get = function (i = 0, n = 0) {
        const t = i + n;

        let r = [];

        for (; i < t; i++) {
            r.push(this[i]);
        }

        return r;
    };


    class PropsArray {
        constructor(count = 0, props = []) {
            this.count = count;
            this.props = props;
            this.values = new Float32Array(count * props.length);
        }

        get length() {
            return this.values.length;
        }

        set(a = [], i = 0) {
            this.values.set(a, i);
        }

        setMap(o = {}, i = 0) {
            this.set(Object.values(o), i);
        }

        get(i = 0) {
            return this.values.get(i, this.props.length);
        }

        getMap(i = 0) {
            return this.get(i).reduce(
                (r, v, i) => ({
                    ...r,
                    ...{[this.props[i]]: v}
                }),
                {}
            );
        }

        forEach(cb) {
            let i = 0;

            for (; i < this.length; i += this.props.length) {
                cb(this.get.call(this, i), i, this);
            }
        }

        map(cb) {
            let i = 0;

            for (; i < this.length; i += this.props.length) {
                this.set(cb(this.get.call(this, i), i, this), i);
            }
        }
    }

    !function () {
        "use strict";
        var r = .5 * (Math.sqrt(3) - 1), e = (3 - Math.sqrt(3)) / 6, t = 1 / 6, a = (Math.sqrt(5) - 1) / 4,
            o = (5 - Math.sqrt(5)) / 20;

        function i(r) {
            var e;
            e = "function" == typeof r ? r : r ? function () {
                var r = 0, e = 0, t = 0, a = 1, o = (i = 4022871197, function (r) {
                    r = r.toString();
                    for (var e = 0; e < r.length; e++) {
                        var t = .02519603282416938 * (i += r.charCodeAt(e));
                        t -= i = t >>> 0, i = (t *= i) >>> 0, i += 4294967296 * (t -= i)
                    }
                    return 2.3283064365386963e-10 * (i >>> 0)
                });
                var i;
                r = o(" "), e = o(" "), t = o(" ");
                for (var n = 0; n < arguments.length; n++) (r -= o(arguments[n])) < 0 && (r += 1), (e -= o(arguments[n])) < 0 && (e += 1), (t -= o(arguments[n])) < 0 && (t += 1);
                return o = null, function () {
                    var o = 2091639 * r + 2.3283064365386963e-10 * a;
                    return r = e, e = t, t = o - (a = 0 | o)
                }
            }(r) : Math.random, this.p = n(e), this.perm = new Uint8Array(512), this.permMod12 = new Uint8Array(512);
            for (var t = 0; t < 512; t++) this.perm[t] = this.p[255 & t], this.permMod12[t] = this.perm[t] % 12
        }

        function n(r) {
            var e, t = new Uint8Array(256);
            for (e = 0; e < 256; e++) t[e] = e;
            for (e = 0; e < 255; e++) {
                var a = e + ~~(r() * (256 - e)), o = t[e];
                t[e] = t[a], t[a] = o
            }
            return t
        }

        i.prototype = {
            grad3: new Float32Array([1, 1, 0, -1, 1, 0, 1, -1, 0, -1, -1, 0, 1, 0, 1, -1, 0, 1, 1, 0, -1, -1, 0, -1, 0, 1, 1, 0, -1, 1, 0, 1, -1, 0, -1, -1]),
            grad4: new Float32Array([0, 1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1, 0, -1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 1, 0, 1, 1, 1, 0, 1, -1, 1, 0, -1, 1, 1, 0, -1, -1, -1, 0, 1, 1, -1, 0, 1, -1, -1, 0, -1, 1, -1, 0, -1, -1, 1, 1, 0, 1, 1, 1, 0, -1, 1, -1, 0, 1, 1, -1, 0, -1, -1, 1, 0, 1, -1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, -1, 1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1, 0, -1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 0]),
            noise2D: function (t, a) {
                var o, i, n = this.permMod12, f = this.perm, s = this.grad3, v = 0, h = 0, l = 0, u = (t + a) * r,
                    d = Math.floor(t + u), p = Math.floor(a + u), M = (d + p) * e, m = t - (d - M), c = a - (p - M);
                m > c ? (o = 1, i = 0) : (o = 0, i = 1);
                var y = m - o + e, w = c - i + e, g = m - 1 + 2 * e, A = c - 1 + 2 * e, x = 255 & d, q = 255 & p,
                    D = .5 - m * m - c * c;
                if (D >= 0) {
                    var S = 3 * n[x + f[q]];
                    v = (D *= D) * D * (s[S] * m + s[S + 1] * c)
                }
                var U = .5 - y * y - w * w;
                if (U >= 0) {
                    var b = 3 * n[x + o + f[q + i]];
                    h = (U *= U) * U * (s[b] * y + s[b + 1] * w)
                }
                var F = .5 - g * g - A * A;
                if (F >= 0) {
                    var N = 3 * n[x + 1 + f[q + 1]];
                    l = (F *= F) * F * (s[N] * g + s[N + 1] * A)
                }
                return 70 * (v + h + l)
            },
            noise3D: function (r, e, a) {
                var o, i, n, f, s, v, h, l, u, d, p = this.permMod12, M = this.perm, m = this.grad3,
                    c = (r + e + a) * (1 / 3), y = Math.floor(r + c), w = Math.floor(e + c), g = Math.floor(a + c),
                    A = (y + w + g) * t, x = r - (y - A), q = e - (w - A), D = a - (g - A);
                x >= q ? q >= D ? (s = 1, v = 0, h = 0, l = 1, u = 1, d = 0) : x >= D ? (s = 1, v = 0, h = 0, l = 1, u = 0, d = 1) : (s = 0, v = 0, h = 1, l = 1, u = 0, d = 1) : q < D ? (s = 0, v = 0, h = 1, l = 0, u = 1, d = 1) : x < D ? (s = 0, v = 1, h = 0, l = 0, u = 1, d = 1) : (s = 0, v = 1, h = 0, l = 1, u = 1, d = 0);
                var S = x - s + t, U = q - v + t, b = D - h + t, F = x - l + 2 * t, N = q - u + 2 * t,
                    C = D - d + 2 * t, P = x - 1 + .5, T = q - 1 + .5, _ = D - 1 + .5, j = 255 & y, k = 255 & w,
                    z = 255 & g, B = .6 - x * x - q * q - D * D;
                if (B < 0) o = 0; else {
                    var E = 3 * p[j + M[k + M[z]]];
                    o = (B *= B) * B * (m[E] * x + m[E + 1] * q + m[E + 2] * D)
                }
                var G = .6 - S * S - U * U - b * b;
                if (G < 0) i = 0; else {
                    var H = 3 * p[j + s + M[k + v + M[z + h]]];
                    i = (G *= G) * G * (m[H] * S + m[H + 1] * U + m[H + 2] * b)
                }
                var I = .6 - F * F - N * N - C * C;
                if (I < 0) n = 0; else {
                    var J = 3 * p[j + l + M[k + u + M[z + d]]];
                    n = (I *= I) * I * (m[J] * F + m[J + 1] * N + m[J + 2] * C)
                }
                var K = .6 - P * P - T * T - _ * _;
                if (K < 0) f = 0; else {
                    var L = 3 * p[j + 1 + M[k + 1 + M[z + 1]]];
                    f = (K *= K) * K * (m[L] * P + m[L + 1] * T + m[L + 2] * _)
                }
                return 32 * (o + i + n + f)
            },
            noise4D: function (r, e, t, i) {
                var n, f, s, v, h, l, u, d, p, M, m, c, y, w, g, A, x, q = this.perm, D = this.grad4,
                    S = (r + e + t + i) * a, U = Math.floor(r + S), b = Math.floor(e + S), F = Math.floor(t + S),
                    N = Math.floor(i + S), C = (U + b + F + N) * o, P = r - (U - C), T = e - (b - C), _ = t - (F - C),
                    j = i - (N - C), k = 0, z = 0, B = 0, E = 0;
                P > T ? k++ : z++, P > _ ? k++ : B++, P > j ? k++ : E++, T > _ ? z++ : B++, T > j ? z++ : E++, _ > j ? B++ : E++;
                var G = P - (l = k >= 3 ? 1 : 0) + o, H = T - (u = z >= 3 ? 1 : 0) + o,
                    I = _ - (d = B >= 3 ? 1 : 0) + o, J = j - (p = E >= 3 ? 1 : 0) + o,
                    K = P - (M = k >= 2 ? 1 : 0) + 2 * o, L = T - (m = z >= 2 ? 1 : 0) + 2 * o,
                    O = _ - (c = B >= 2 ? 1 : 0) + 2 * o, Q = j - (y = E >= 2 ? 1 : 0) + 2 * o,
                    R = P - (w = k >= 1 ? 1 : 0) + 3 * o, V = T - (g = z >= 1 ? 1 : 0) + 3 * o,
                    W = _ - (A = B >= 1 ? 1 : 0) + 3 * o, X = j - (x = E >= 1 ? 1 : 0) + 3 * o, Y = P - 1 + 4 * o,
                    Z = T - 1 + 4 * o, $ = _ - 1 + 4 * o, rr = j - 1 + 4 * o, er = 255 & U, tr = 255 & b, ar = 255 & F,
                    or = 255 & N, ir = .6 - P * P - T * T - _ * _ - j * j;
                if (ir < 0) n = 0; else {
                    var nr = q[er + q[tr + q[ar + q[or]]]] % 32 * 4;
                    n = (ir *= ir) * ir * (D[nr] * P + D[nr + 1] * T + D[nr + 2] * _ + D[nr + 3] * j)
                }
                var fr = .6 - G * G - H * H - I * I - J * J;
                if (fr < 0) f = 0; else {
                    var sr = q[er + l + q[tr + u + q[ar + d + q[or + p]]]] % 32 * 4;
                    f = (fr *= fr) * fr * (D[sr] * G + D[sr + 1] * H + D[sr + 2] * I + D[sr + 3] * J)
                }
                var vr = .6 - K * K - L * L - O * O - Q * Q;
                if (vr < 0) s = 0; else {
                    var hr = q[er + M + q[tr + m + q[ar + c + q[or + y]]]] % 32 * 4;
                    s = (vr *= vr) * vr * (D[hr] * K + D[hr + 1] * L + D[hr + 2] * O + D[hr + 3] * Q)
                }
                var lr = .6 - R * R - V * V - W * W - X * X;
                if (lr < 0) v = 0; else {
                    var ur = q[er + w + q[tr + g + q[ar + A + q[or + x]]]] % 32 * 4;
                    v = (lr *= lr) * lr * (D[ur] * R + D[ur + 1] * V + D[ur + 2] * W + D[ur + 3] * X)
                }
                var dr = .6 - Y * Y - Z * Z - $ * $ - rr * rr;
                if (dr < 0) h = 0; else {
                    var pr = q[er + 1 + q[tr + 1 + q[ar + 1 + q[or + 1]]]] % 32 * 4;
                    h = (dr *= dr) * dr * (D[pr] * Y + D[pr + 1] * Z + D[pr + 2] * $ + D[pr + 3] * rr)
                }
                return 27 * (n + f + s + v + h)
            }
        }, i._buildPermutationTable = n, "undefined" != typeof define && define.amd && define(function () {
            return i
        }), "undefined" != typeof exports ? exports.SimplexNoise = i : "undefined" != typeof window && (window.SimplexNoise = i), "undefined" != typeof module && (module.exports = i)
    }();

    "use strict";

    const backgroundColor = "rgba(0,0,10,0.5)";
    const baseHue = rand(360);
    const rangeHue = 180;
    const tentacleCount = 30;
    const segmentCountMin = 10;
    const segmentCountMax = 20;
    const segmentLengthMin = 20;
    const segmentLengthMax = 40;
    const colonyRadius = 200;

    let canvas;
    let ctx;
    let center;
    let mouse;
    let tick;
    let simplex;
    let tentacle;
    let tentacles;

    class Tentacle {
        constructor(x, y, segmentNum, baseLength, baseDirection) {
            this.base = [x, y];
            this.position = [x, y];
            this.target = [x, y];
            this.segmentNum = segmentNum;
            this.baseLength = baseLength;
            this.baseDirection = baseDirection;
            this.segmentProps = ["x1", "y1", "x2", "y2", "l", "d", "h"];
            this.segments = new PropsArray(segmentNum, this.segmentProps);
            this.follow = false;

            let i = this.segments.length - this.segmentProps.length;
            let x1, y1, x2, y2, l, d, h;

            l = this.baseLength;
            d = this.baseDirection;

            for (; i >= 0; i -= this.segmentProps.length) {
                x1 = x2 || this.position[0];
                y1 = y2 || this.position[1];
                x2 = x1 - l * cos(d);
                y2 = y1 - l * sin(d);
                d += 0.309;
                l *= 0.98;
                h = baseHue + fadeIn(i, this.segments.length) * rangeHue;
                this.segments.set([x1, y1, x2, y2, l, d, h], i);
            }
        }

        setCtx(ctx) {
            this.ctx = ctx;
        }

        setTarget(target) {
            this.target = target;
        }

        updateBase() {
            let t = simplex.noise3D(this.base[0] * 0.005, this.base[1] * 0.005, tick * 0.005) * TAU;

            this.base.lerp([
                    this.base[0] + 20 * cos(t),
                    this.base[1] + 20 * sin(t)],
                0.025);
        }

        async update() {
            let target = this.position;
            let i = this.segments.length - this.segmentProps.length;
            let promises = [];

            this.position.lerp(this.target, 0.015);
            !this.follow && this.updateBase();

            for (; i >= 0; i -= this.segmentProps.length) {
                promises.push(
                    new Promise(resolve => {
                        let [x1, y1, x2, y2, l, d, h] = this.segments.get(i);
                        let t, n, tn;

                        x1 = target[0];
                        y1 = target[1];
                        t = angle(x1, y1, x2, y2);
                        n = simplex.noise3D(
                            x1 * 0.005,
                            y1 * 0.005,
                            (i + tick) * 0.005);

                        tn = t + n * PI * 0.0125;
                        x2 = x1 + l * cos(tn);
                        y2 = y1 + l * sin(tn);
                        d = t;

                        target = [x2, y2];

                        this.segments.set([x1, y1, x2, y2, l, d], i);
                        this.drawSegment(x1, y1, x2, y2, h, n, i);

                        resolve();
                    }));

            }

            await Promise.all(promises);
        }

        drawSegment(x1, y1, x2, y2, h, n, i) {
            const fn = fadeInOut(1 + n, 2);
            const fa = fadeInOut(i, this.segments.length);
            const a = 0.25 * (fn + fa);

            this.ctx.beginPath();
            this.ctx.strokeStyle = `hsla(${h}, 50%, 50%, ${a})`;
            this.ctx.moveTo(x2, y2);
            this.ctx.lineTo(x1, y1);
            this.ctx.stroke();
            this.ctx.beginPath();

            this.ctx.closePath();
            this.ctx.strokeStyle = `hsla(${h}, 50%, 50%, ${a + 0.5})`;
            this.ctx.arc(x1, y1, fn * 3, 0, TAU);
            this.ctx.stroke();
            this.ctx.closePath();
        }
    }


    function setup() {
        tick = 0;
        simplex = new SimplexNoise();
        mouse = [0, 0];
        createCanvas();
        resize();
        tentacles = [];

        let i, t;

        for (i = 0; i < tentacleCount; i++) {
            t = i / tentacleCount * TAU;
            tentacle = new Tentacle(
                center[0] + colonyRadius * cos(rand(TAU)),
                center[1] + colonyRadius * sin(rand(TAU)),
                round(randIn(segmentCountMin, segmentCountMax)),
                round(randIn(segmentLengthMin, segmentLengthMax)),
                t);

            tentacle.setCtx(ctx.a);
            tentacles.push(tentacle);
        }

        loop();
    }

    function createCanvas() {
        canvas = {
            a: document.createElement("canvas"),
            b: document.createElement("canvas")
        };

        canvas.b.style = `
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
	`;
        document.body.appendChild(canvas.b);
        ctx = {
            a: canvas.a.getContext("2d"),
            b: canvas.b.getContext("2d")
        };

        center = [0.5 * canvas.a.width, 0.5 * canvas.a.height];
    }

    function resize() {
        const {innerWidth, innerHeight} = window;

        canvas.a.width = innerWidth;
        canvas.a.height = innerHeight;

        ctx.a.drawImage(canvas.b, 0, 0);

        canvas.b.width = innerWidth;
        canvas.b.height = innerHeight;

        ctx.b.drawImage(canvas.a, 0, 0);

        center[0] = 0.5 * canvas.a.width;
        center[1] = 0.5 * canvas.a.height;
    }

    function renderBackground() {
        ctx.a.clearRect(0, 0, canvas.b.width, canvas.b.height);
        ctx.b.fillStyle = backgroundColor;
        ctx.b.fillRect(0, 0, canvas.a.width, canvas.a.height);
    }

    function renderGlow() {
        ctx.b.save();
        ctx.b.filter = "blur(8px) brightness(200%)";
        ctx.b.globalCompositeOperation = "lighter";
        ctx.b.drawImage(canvas.a, 0, 0);
        ctx.b.restore();

        ctx.b.save();
        ctx.b.filter = "blur(4px) brightness(200%)";
        ctx.b.globalCompositeOperation = "lighter";
        ctx.b.drawImage(canvas.a, 0, 0);
        ctx.b.restore();
    }

    function renderToScreen() {
        ctx.b.save();
        ctx.b.globalCompositeOperation = "lighter";
        ctx.b.drawImage(canvas.a, 0, 0);
        ctx.b.restore();
    }

    async function loop() {
        tick++;

        renderBackground();

        await Promise.all(tentacles.map(tentacle => tentacle.update()));

        renderGlow();
        renderToScreen();

        window.requestAnimationFrame(loop);
    }

    window.addEventListener("load", setup);
    window.addEventListener("resize", resize);
    window.addEventListener("mousemove", e => {
        tentacles.forEach((tentacle, i) => {
            const t = i / tentacles.length * TAU;
            tentacle.setTarget([e.clientX + colonyRadius * cos(t + tick * 0.05), e.clientY + colonyRadius * sin(t + tick * 0.05)]);
            tentacle.follow = true;
        });
    });
    window.addEventListener("mouseout", () => {
        tentacles.forEach(tentacle => {
            tentacle.base = [
                center[0] + colonyRadius * cos(rand(TAU)),
                center[1] + colonyRadius * sin(rand(TAU))];

            tentacle.setTarget(tentacle.base);
            tentacle.follow = false;
        });
    });
</script>
</html>
